package com.ltmonitor.server.netty;

import com.ltmonitor.jt808.service.IGpsConnectionService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ltmonitor.app.GlobalConfig;
import com.ltmonitor.app.GpsConnection;
import com.ltmonitor.jt808.service.IJT808Server;
import com.ltmonitor.jt808.service.IMessageProcessService;
/**
 * 基于netty 框架的tcp 服务器
 * @author admin
 *
 */
@Service("jt808TcpNettyServer")
public class JT808TcpNettyServer implements IJT808Server {
	private static Logger logger = Logger.getLogger(JT808TcpNettyServer.class);
	private int port;


	@Autowired
	private IMessageProcessService messageProcessService;

	@Autowired
	private IGpsConnectionService gpsConnectionService;

	//private ProtocolServerHandler nettyTcpSeverHandler;
	EventLoopGroup bossGroup;
	EventLoopGroup workerGroup;
	ChannelFuture f;
	ServerBootstrap b;

	public boolean start()  {
		bossGroup = new NioEventLoopGroup(); // (1)
		workerGroup = new NioEventLoopGroup();
		//
		try {
			b = new ServerBootstrap(); // (2)
			b.group(bossGroup, workerGroup)
					.channel(NioServerSocketChannel.class) // (3)
					.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
						@Override
						public void initChannel(SocketChannel ch)
								throws Exception {
							//超过20分钟未收到客户端消息则自动断开客户端连接
							ch.pipeline().addLast("idleStateHandler",
									new IdleStateHandler(20, 0, 0, TimeUnit.MINUTES));
							ch.pipeline().addLast("decoder",
									new ProtocolDecoder());
							ch.pipeline().addLast("encoder",
									new ByteArrayEncoder());
							ProtocolServerHandler handler = new ProtocolServerHandler();
							handler.setMessageProcessService(messageProcessService);
							handler.setGpsConnectionService(gpsConnectionService);
							ch.pipeline().addLast(handler);
						}
					}).option(ChannelOption.SO_BACKLOG, 128) // (5)
					.childOption(ChannelOption.SO_KEEPALIVE, false); // (6)

			// 绑定端口，开始接收进来的连接
			port = GlobalConfig.listenPort;
			f = b.bind(port).sync();

			// 等待服务器 socket 关闭 。
			// 在这个例子中，这不会发生，但你可以优雅地关闭你的服务器。
			// f.channel().closeFuture().sync();
			return true;
		} catch(Exception ex)
		{
			logger.error(ex.getMessage(),ex);
		}
		return false;
	}

	@Override
	public void Stop() {
		logger.error("netty server stop");
		try {
			// f.channel().closeFuture().sync();
			f.channel().close();
		} catch (Exception ex) {
			logger.error(ex.getMessage(), ex);
		}
		try {
			workerGroup.shutdownGracefully();
		} catch (Exception ex) {
			logger.error(ex.getMessage(), ex);
		}
		try {
			bossGroup.shutdownGracefully();
		} catch (Exception ex) {
			logger.error(ex.getMessage(), ex);
		}
	}

	@Override
	public Collection<GpsConnection> getGpsConnections() {
		return this.gpsConnectionService.getAllConnections();
	}


	public GpsConnection getConnection(String simNo) {
		if (simNo.length() > 11)
			simNo = simNo.substring(1);
		GpsConnection conn = this.gpsConnectionService.getConnection(simNo);
		return conn;
	}

	@Override
	public boolean send(String simNo, byte[] msg) {
		GpsConnection conn = getConnection(simNo);
		if (conn != null && conn.getNettyChannel() != null) {
			conn.getNettyChannel().writeAndFlush(msg);
			return true;
		}
		return false;
	}

	@Override
	public boolean isOnline(String simNo) {
		if (simNo == null || simNo.length() == 0) {
			logger.error(simNo + "不能为空");
			return false;
		}
		GpsConnection conn = this.getConnection(simNo);
		if (conn != null && conn.getNettyChannel() != null) {
			return conn.isConnected();
		} else {
			logger.error(simNo + "没有此链接,判断离线");
		}
		return false;
	}


	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public IMessageProcessService getMessageProcessService() {
		return messageProcessService;
	}

	public void setMessageProcessService(IMessageProcessService messageProcessService) {
		this.messageProcessService = messageProcessService;
	}

}
